package io.summer.basis.api;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.summer.basis.enums.IEnumCode;
import io.summer.basis.excepts.AppException;
import lombok.Data;
import lombok.experimental.Accessors;

import java.util.HashMap;
import java.util.Map;

/**
 * @author Moonlight
 */
@Data
@Accessors(chain = true)
public class ApiResponse<T> implements IEnumCode {
  public String toSimpleString() {
    return "{" +
      "\"code\":" + code + "," +
      "\"message\":" + message +
      "}";
  }

  /**
   * 响应码
   */
  private int code;

  /**
   * 响应消息
   */
  private String message;

  /**
   * 响应数据
   */
  @JsonInclude(JsonInclude.Include.NON_NULL)
  private T data;

  private static String formatMessage(String msg, Object... params) {
    return String.format(msg, params);
  }

  public static <T> ApiResponse<T> response(boolean ok) {
    return ok ? ok() : fail();
  }

  public static <T> ApiResponse<T> response(T data, IEnumCode enumCode, Object... params) {
    return response(enumCode.getCode(), formatMessage(enumCode.getMessage(), params), data);
  }

  public static <T> ApiResponse<T> response(IEnumCode enumCode, Object... params) {
    return response(null, enumCode, params);
  }

  public static <T> ApiResponse<T> response(int code, String message, T data) {
    ApiResponse<T> response = new ApiResponse<>();
    response.setCode(code).setMessage(message).setData(data);
    return response;
  }

  public static <T> ApiResponse<T> response(int code, String message, Object... params) {
    return response(code, formatMessage(message, params), (T) null);
  }

  public static <T> ApiResponse<T> ok() {
    return ok(null);
  }

  public static <T> ApiResponse<T> ok(T data) {
    return response(data, ApiCode.OK);
  }

  public static <T> ApiResponse<T> ok(T data, String message, Object... params) {
    return response(IEnumCode.SUCCESS, formatMessage(message, params), data);
  }

  public static <T> ApiResponse<T> fail(String message, Object... params) {
    return response(IEnumCode.FRAME_ERROR, message, params);
  }

  public static <T> ApiResponse<T> fail() {
    return response(ApiCode.FAILED);
  }

  public static Object[] params(Object... params) {
    return params;
  }

  public boolean isOk() {
    return code == IEnumCode.SUCCESS;
  }

  @JsonIgnore
  public boolean isFailed() {
    return !isOk();
  }

  @SuppressWarnings({"unchecked"})
  public ApiResponse<Map<Object, Object>> putData(Object key, Object value) {
    if (data == null) {
      Map<Object, Object> d = new HashMap<>(2);
      setData((T) d);
    } else if (!(data instanceof Map)) {
      throw new AppException("ApiResponse putData, data type is not a map!");
    }
    ((Map<Object, Object>) data).put(key, value);
    return (ApiResponse<Map<Object, Object>>) this;
  }
}
